package org.tnc.budget.webapp.controller;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.tnc.budget.model.AttachmentTable;
import org.tnc.budget.model.BudgetCenter;
import org.tnc.budget.model.EventTable;
import org.tnc.budget.service.BudgetManager;
import org.tnc.budget.service.EventManager;
import org.tnc.budget.webapp.util.AuthCryptException;
import org.tnc.budget.webapp.util.BudgetConstants;
import org.tnc.budget.webapp.util.DESHelper;
import org.tnc.budget.webapp.util.DateUtils;
import org.tnc.budget.webapp.util.RandomFileRenamePolicy;
import org.tnc.model.User;
import org.tnc.service.UserManager;

import com.opensymphony.oscache.base.NeedsRefreshException;
import com.oreilly.servlet.MultipartRequest;

/**
 * 
 * 上传用户的约会数据：Email, 主题，开始日期，开始时间，结束日期，结束时间，预算中心名称，地点，说明
 * 
 * 
 * @author houjj | 2011-4-3 下午04:14:23
 */

public class AppointmentController implements Controller, BudgetConstants {

	private Logger log = Logger.getLogger(AppointmentController.class);

	private int maxUploadSize = DEFAULT_MAX_UPLOAD_SIZE;
	private String uploadDir;
	private String encodingCharset = DEFAULT_FILE_ENCODING_CHARSET;

	private RandomFileRenamePolicy rfrp = new RandomFileRenamePolicy();
	private EventManager eventManager;
	private UserManager userManager;
	private BudgetManager budgetManager;

	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}

	public void setBudgetManager(BudgetManager budgetManager) {
		this.budgetManager = budgetManager;
	}

	/**
	 * Constructor of the object.
	 */
	public AppointmentController() {
		super();
	}

	/**
	 * 
	 * 采用Cos上传文件的主要方法类
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) {

		// operation=sych, del
		printRequestParameters(request);

		String emailParam = "";
		String authParam = "";
		int result = 0;

		User u = null;
		String newPwd = "";
		try {
			emailParam = ServletRequestUtils.getStringParameter(request,
					"email");
			authParam = ServletRequestUtils.getStringParameter(request, "data");
			if (emailParam == null) {
				throw new ServletRequestBindingException("parameter 'email'");
			}

			if (authParam == null) {
				throw new ServletRequestBindingException("parameter 'data'");
			}

			u = userManager.getUserByUserEmail(emailParam);
			String pwd = u.getPassword();
			newPwd = pwd.substring(SUB_PASSWORD_START_INDEX,
					SUB_PASSWORD_END_INDEX);
			String ddata = DESHelper.desDecrypt(authParam, newPwd);
			if (log.isDebugEnabled())
				log.debug("Decrypted Data:" + ddata);
			// data的数据格式2011/4/17 10:32:11
			if (!isValidData(ddata)) {
				throw new AuthCryptException("Format of decrypted data error");
			}

		} catch (ServletRequestBindingException e) {
			log.warn("Parameter 'email' or 'data' not exist, " + e.getMessage());
			result = -4;
		} catch (UsernameNotFoundException e) {
			log.warn("User not exist");
			result = -2;
		} catch (AuthCryptException e) {
			log.error("Decrypt Error", e);
			result = -3;
		} catch (Exception e) {
			result = -1;
		}

		//
		if (result == 0) {

			String uploadDir = getUploadDir();
			String subDir = this.getFileDirectoryName();
			String storePath = prepareStorageDirectory(uploadDir, subDir);

			// 上传文件总的大小
			int maxPostSize = this.getMaxUploadSize();
			// response的编码为"gb2312",同时采用缺省的文件名冲突解决策略,实现上传
			// 第一个参数为HttpServletRequest 第二参数: maxPostSize 上传文件大小 第三个目录上传文件目录
			MultipartRequest multi;

			try {
				multi = new MultipartRequest(request, storePath, maxPostSize,
						DEFAULT_FILE_ENCODING_CHARSET, rfrp, newPwd);
				// 输出反馈信息

				String data = multi.getParameter("data");
				JSONObject jsonData = new JSONObject(data);
				// 预算中心
				String budgetName = jsonData.getString("Buget");
				BudgetCenter budgetCenter = budgetManager
						.getBudgetByName(budgetName);
				if (budgetCenter == null) {
					throw new IllegalArgumentException(
							"Budget center not exist:" + budgetName);
				}

				String clientEventId = jsonData.getString("ID");
				String eventBody = jsonData.getString("Body");
				String address = jsonData.getString("Location");
				String subject = jsonData.getString("Subject");

				boolean eventPassedReview = false, eventNeedReview = false;

				List<EventTable> eventList = eventManager
						.getEventByClientEventID(u.getId(), clientEventId);
				for (EventTable event : eventList) {
					if (event.getIsReviewed() == null || event.getIsPassed() == null ||
							!event.getIsReviewed() || !event.getIsPassed()) {
						this.eventManager.deleteEventTable(event);
						eventNeedReview = event.getIsReviewed() == true && event.getIsPassed() == false;
						log.info("Event is exist, id:" + event.getId()
								+ ", client id:" + clientEventId);
					} else {
						eventPassedReview = true;
					}
				}

				// 如果约会事件存在，清除附件
				String startDay = jsonData.getString("StartDay");
				String startTime = jsonData.getString("StartTime");
				String endDay = jsonData.getString("EndDay");
				String endTime = jsonData.getString("EndTime");
				
				int autoReviewDOM = eventManager.getAutoReviewDayOfMonth();
				
				Calendar c = Calendar.getInstance();
				c.set(Calendar.HOUR_OF_DAY, 0);
				c.set(Calendar.MINUTE, 0);
				c.set(Calendar.SECOND, 0);
				c.set(Calendar.MILLISECOND, 0);

				if (autoReviewDOM < c.get(Calendar.DAY_OF_MONTH)) {
					// 当前日期大于自动审核日期
					String d = startDay.substring(startDay.length() - 2);
					String m = startDay.substring(startDay.length() - 5, startDay.length() - 3);
					String y = startDay.substring(0,4);
					
					c.set(Calendar.DAY_OF_MONTH, 1);
					long curtime = c.getTimeInMillis();
				
					c.set(Integer.parseInt(y), Integer.parseInt(m)-1, Integer.parseInt(d));
					// 事件开始日期是上个月的
					if (curtime > c.getTimeInMillis()) {
						eventPassedReview = true;
					}
				}
				
				if (!eventPassedReview) {
					// 未审核的事件可以更新
					List<AttachmentTable> attachmentTables = getAttachmentInfos(
							subDir, multi);
					// 分割时间段，以天为单位
					Queue<Date> ddQueue = DateUtils.splitDate(startDay + " "
							+ startTime, endDay + " " + endTime);

					Date begin = ddQueue.poll();
					while (!ddQueue.isEmpty()) {
						Date end = ddQueue.poll();

						if (begin.equals(end)) {
							// 如果最后两个时间相同，抛弃该时间段
							break;
						} else {

							SimpleDateFormat dateFormat = new SimpleDateFormat(
									"yyyy-MM-dd");
							SimpleDateFormat timeFormat = new SimpleDateFormat(
									"HH:mm:ss");

							EventTable event = new EventTable();
							event.setStartDate(dateFormat.format(begin));
							event.setStartTime(timeFormat.format(begin));
							event.setEndDate(dateFormat.format(end));
							event.setEndTime(timeFormat.format(end));

							// 事件详细信息
							event.setEventText(eventBody);
							event.setEventId(clientEventId);
							event.setEventAdd(address);
							event.setEventName(subject);
							event.setIsValid(true);
							event.setEventDate(new Date());

							List<AttachmentTable> nl = new ArrayList<AttachmentTable>();
							for (AttachmentTable at : attachmentTables) {
								AttachmentTable newAt = new AttachmentTable(at);
								newAt.setEventTable(event);
								nl.add(newAt);
							}

							event.getAttachmentTables().addAll(nl);
							event.setBudgetCenter(budgetCenter);
							event.setUser(u);

							if (eventNeedReview) {
								User bcMgr = event.getBudgetCenter().getUser();
								if (bcMgr != null)
									userManager.sendEmailTo("["+event.getBudgetCenter().getBcName() + "]待审批事件",
											"日期：" + event.getStartDate() + " " + event.getStartTime() + "~" + event.getEndTime() + "\n" + 
											"用户：" + u.getFullName() , bcMgr, u);
							}

							// 只保存持续时间不超过24小时的事件。
							if (event.getDuration() < 24.0) {
								this.eventManager.saveEventTable(event);
							} else {
								log.warn("Discarded event that has duration >= 24.0 hours.");
							}
						}

						// 下一条事件的开始时间为上一条事件的结束时间
						begin = end;
					}
					
					if (attachmentTables.size() > 0)
						attachmentTables.clear();
				}
				result = 1;
			} catch (IOException e) {
				e.printStackTrace();
				log.error("Upload file error", e);
				result = -1;
			} catch (JSONException e) {
				result = -5;
				log.error("Json fetech data Error", e);
			} catch (AuthCryptException e) {
				result = -3;
				log.error("Decrypt Error", e);
			} catch (Exception e1) {
				result = -1;
				log.error("Appointment upload file exception", e1);
			}
		}

		// 返回结果数据
		PrintWriter out;
		try {
			out = response.getWriter();
			out.println(result);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
			log.error("Write reponse message failed when upload file", e);
		}

		return null;
	}

	private List<AttachmentTable> getAttachmentInfos(String subDir,
			MultipartRequest multi) {
		List<AttachmentTable> attachmentTables = new ArrayList<AttachmentTable>();
		StringBuffer resp = new StringBuffer("Upload file, ");
		Enumeration files = multi.getFileNames();
		// 遍历上传的文件
		while (files.hasMoreElements()) {
			// 获取上传文件的对应的名称
			String name = (String) files.nextElement();

			// 获取名称对应的文件
			File f = multi.getFile(name);
			if (f != null) {
				// 获取对应名称文件的路徑信息
				String newName = multi.getFilesystemName(name);
				String originalFileName = multi.getOriginalFileName(name);
				// 进行相关的数据库日志等业务操作

				AttachmentTable at = new AttachmentTable();
				at.setChangeName(newName);
				at.setSourceName(originalFileName);
				at.setFileUri(subDir + "/" + newName);

				attachmentTables.add(at);
				// ......
				String lastFileName = "[ new name:" + newName
						+ " - original filename:" + originalFileName + "] ";
				resp.append(lastFileName);

			}
		}
		log.info(resp.toString());
		return attachmentTables;
	}

	/**
	 * 验证日期是否合法 yyyy-mm-dd hh:mm:ss
	 * 
	 * @param ddata
	 * @return
	 */
	public static boolean isValidData(String ddata) {
		boolean result = false;
		String[] d = ddata.split("-");
		if (d.length > 2) {
			result = true;
		}
		d = ddata.split("/");
		if (d.length > 2) {
			result = true;
		}
		return result;
	}

	private String prepareStorageDirectory(String storePath, String dirName) {
		// 上传文件目录

		if (!storePath.endsWith("/") || !storePath.endsWith("\\")) {
			storePath = storePath + File.separator;
		}

		storePath = storePath + dirName;
		// 存储在创建上传文件目录
		File file = new File(storePath);
		if (!file.isDirectory()) {
			try {
				FileUtils.forceMkdir(file);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return storePath;
	}

	private void printRequestParameters(HttpServletRequest request) {
		Map params = request.getParameterMap();
		Set s = params.keySet();
		Iterator sit = s.iterator();
		while (sit.hasNext()) {
			Object o = sit.next();
			String[] v = (String[]) params.get(o);
			log.info(o + "=" + v[0]);
		}
	}

	private final static String getWebrootPath() {
		String root = AppointmentController.class.getResource("/").getFile();
		try {
			root = new File(root).getParentFile().getParentFile()
					.getCanonicalPath();
			root += File.separator;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return root;
	}

	/**
	 * 
	 * @return 年月的字符串格式：201104
	 */
	public String getFileDirectoryName() {
		SimpleDateFormat format2 = new SimpleDateFormat("yyyyMM");
		String fileDirName = format2.format(new Date());
		return fileDirName;
	}

	/**
	 * 上传的文件存储的目录
	 * 
	 * @return
	 */
	public String getUploadDir() {

		if (uploadDir == null || "".equals(uploadDir)) {
			uploadDir = getWebrootPath() + DEFAULT_COS_UPLOAD_DIR;
		}
		return uploadDir;
	}

	public void setUploadDir(String uploadDir) {
		this.uploadDir = uploadDir;
	}

	public String getEncodingCharset() {
		return encodingCharset;
	}

	public void setEncodingCharset(String encodingCharset) {
		this.encodingCharset = encodingCharset;
	}

	public int getMaxUploadSize() {
		return maxUploadSize;
	}

	public void setMaxUploadSize(int maxUploadSize) {
		this.maxUploadSize = maxUploadSize;
	}

	public void setEventManager(EventManager eventManager) {
		this.eventManager = eventManager;
	}

}
